/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.service.manage;

import cn.ac.nercis.pes.model.dto.common.Result;
import cn.ac.nercis.pes.model.dto.common.ResultCode;
import cn.ac.nercis.pes.model.dto.manage.TestedUnitDTO;
import cn.ac.nercis.pes.repository.dal.manage.TestedUnitRepository;
import cn.ac.nercis.pes.repository.dal.project.ProjectRepository;
import cn.ac.nercis.pes.repository.mapper.manage.TestedUnitMapper;
import cn.ac.nercis.pes.repository.model.base.DeleteFlag;
import cn.ac.nercis.pes.repository.model.manage.TestedUnitDO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 被测单位管理服务
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@Service
public class TestedUnitService {
    private final TestedUnitRepository testedUnitRepository;
    private final ProjectRepository projectRepository;

    @Autowired
    public TestedUnitService(TestedUnitRepository testedUnitRepository, ProjectRepository projectRepository) {
        this.testedUnitRepository = testedUnitRepository;
        this.projectRepository = projectRepository;
    }

    public Page<TestedUnitDTO> findAll(String name, Pageable pageable){
        TestedUnitDO example = TestedUnitDO.builder().name(name).build();
        example.setDeleteFlag(DeleteFlag.NOT_DELETED);
        ExampleMatcher matcher = ExampleMatcher.matchingAll()
                .withMatcher("name",ExampleMatcher.GenericPropertyMatchers.contains());
        return this.testedUnitRepository.findAll(Example.of(example, matcher), pageable)
                .map(TestedUnitMapper.INSTANCE::toDTO);
    }

    public List<TestedUnitDTO> findAll() {
        return this.testedUnitRepository.findAll().stream()
                .map(TestedUnitMapper.INSTANCE::toDTO)
                .collect(Collectors.toList());
    }

    public Result<TestedUnitDTO> findById(String testUnitedId) {
        return this.testedUnitRepository.findById(testUnitedId)
                .map(TestedUnitMapper.INSTANCE::toDTO)
                .map(Result::success)
                .orElse(Result.failed(ResultCode.TESTED_UNIT_NOT_EXIST));
    }

    public Result<TestedUnitDTO> save(TestedUnitDTO testedUnitDTO) {
        if (StringUtils.isEmpty(testedUnitDTO.getName())) {
            return Result.failed("被测单位不能为空！");
        }
        try {
            if (StringUtils.isEmpty(testedUnitDTO.getId())) {
                return create(testedUnitDTO);
            } else {
                return modify(testedUnitDTO);
            }
        }catch (Exception e){
            log.error("保存被测单位出错：",e);
            return Result.failed(ResultCode.FAIL);
        }
    }

    public Result<String> delete(final String id){
        //验证是否被项目引用
        if(projectRepository.existsByTestedUnitId(id)){
            return Result.failed(ResultCode.TESTED_UNIT_REF_EXIST);
        }
        try {
            return testedUnitRepository.findById(id)
                    .map(unitDO -> {
                        testedUnitRepository.delete(unitDO);
                        return unitDO;
                    })
                    .map(unitDO -> Result.success(unitDO.getId()))
                    .orElse(Result.failed(ResultCode.FAIL));
        }catch (Exception ex){
            log.error("删除被测单位出错：",ex);
            return Result.failed(ResultCode.FAIL);
        }
    }

    private Result<TestedUnitDTO> create(TestedUnitDTO testedUnitDTO){
        if(testedUnitRepository.existsByName(testedUnitDTO.getName())){
            return Result.failed(ResultCode.TESTED_UNIT_NAME_EXIST);
        }
        TestedUnitDO unitDO = TestedUnitMapper.INSTANCE.toDO(testedUnitDTO);
        unitDO.setCreateTime(LocalDateTime.now());
        return Optional.of(testedUnitRepository.save(unitDO))
                .map(TestedUnitMapper.INSTANCE::toDTO)
                .map(Result::success)
                .orElse(Result.failed(ResultCode.FAIL));
    }

    private Result<TestedUnitDTO> modify(TestedUnitDTO testedUnitDTO){
        TestedUnitDO source = this.testedUnitRepository.findById(testedUnitDTO.getId()).orElse(null);
        if(Objects.isNull(source)){
            return Result.failed(ResultCode.TESTED_UNIT_NOT_EXIST);
        }
        if(!StringUtils.equals(source.getName(),testedUnitDTO.getName())
                && this.testedUnitRepository.existsByName(testedUnitDTO.getName())){
            return Result.failed(ResultCode.TESTED_UNIT_NAME_EXIST);
        }
        return Optional.of(TestedUnitMapper.INSTANCE.toDO(source,testedUnitDTO))
                .map(unitDO -> {
                    unitDO.setModifyTime(LocalDateTime.now());
                    return unitDO;
                })
                .map(testedUnitRepository::save)
                .map(TestedUnitMapper.INSTANCE::toDTO)
                .map(Result::success)
                .orElse(Result.failed());
    }
}